/*
********************************************************************************
* Copyright (C) 2021, xiang.D <dx_65535@163.com>.
* All right reserved.
*
* File Name   : msg_manager.cc
* Author      :
* Version     : V1.0
* Description :
* Journal     : 2022-02-13 init v1.0
* Brief       : Blog: https://blog.csdn.net/qq_38750572?spm=1001.2014.3001.5343
* Others      :
********************************************************************************
*/

#include <thread>
#include <stdio.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/select.h>
#include "msg_manager.h"

using namespace std;

#define LOGD(fmt, args...) //printf("%d MsgManager D: " fmt, __LINE__, ##args)
#define LOGE(fmt, args...) printf("%d MsgManager E: " fmt, __LINE__, ##args)

const int  MAX_BUF_SIZE = 1024;
const char FIFO_NAME[]  = "/tmp/fifo1"; 

static int init_flag = 0;

static void init(int *fd)
{
    int ret = -1, fp;

    LOGD("init fifo.\n");

    unlink(FIFO_NAME);
    ret = access(FIFO_NAME, F_OK);
    if (ret < 0) {
        ret = mkfifo(FIFO_NAME, 0664);
        if (ret) {
            LOGE("Create fifo named %s failed!\n", FIFO_NAME);
            return;
        }
    }

    LOGD("open fifo!\n");
    fp = open(FIFO_NAME, O_RDWR);
    *fd = fp;
}

static void msg_send(void *pMsg, int size)
{
    static int fd = -1;
    int ret = -1;

    // TODO: Open in init, communication will be a problem.
    fd = open(FIFO_NAME, O_RDWR);
    if (fd < 0) {
        LOGE("Open %s failed!\n", FIFO_NAME);
        return;
    }

    ret = write(fd, pMsg, size);
    if (ret < 0) {
        LOGE("Write data to fifo failed!\n");
    } else {
        LOGD("Write %d data! fd: %d\n", ret, fd);
    }

    close(fd);
    fd = -1;
}

static void data_translate(void *data, PTypeCallBack pCb)
{
    if (!data || !pCb) {
        LOGE("data or pCb is NULL!\n");
        return;    
    }

    SMsgData msg;
    memcpy(&msg, data, sizeof(SMsgData));
    pCb(msg.type, msg.data);
}

static void msg_recv(int fd, PTypeCallBack pCb)
{
    char buff[MAX_BUF_SIZE] = {0};

    if (fd < 0) {
        init(&fd);
        if (fd < 0) {
            LOGE("open fifo(%s) failed!\n", FIFO_NAME);
            return;
        }
    }

    read(fd, buff, MAX_BUF_SIZE);
    data_translate(buff, pCb);
    //close(fd);
}

static void listen_thread(void *p)
{
    int ret = 0;
    fd_set fds;
    SListenParam *pListen = (SListenParam *)p;
    int listenFd = pListen->fd;

    LOGD("listen_thread start! fd: %d\n", listenFd);
    while(1) {
        FD_ZERO(&fds);
        FD_SET(listenFd, &fds);
        ret = select(listenFd + 1, &fds, NULL, NULL, NULL);
        if (ret < 0) {
            LOGE("select failed!\n");
        } else {
            if (!FD_ISSET(listenFd, &fds)) {
                LOGE("No this fd!\n");
                continue;
            }
            msg_recv(listenFd, pListen->cb);
        }
    }
}

void SendMsgEvent(void *pEvent, int size)
{
    if (!pEvent) {
        LOGE("pEvent is NULL!\n");
        return;
    }

    msg_send(pEvent, size);
}

void SetListener(PTypeCallBack pCb)
{
    SListenParam param;

    if (!pCb) {
        LOGE("pCb is NULL!\n");
        return;    
    }

    param.cb = pCb;

    if (!init_flag) {
        init(&param.fd);
        init_flag = 1;
    }

    LOGD("Create listen_thread!\n");
    thread t(listen_thread, &param);
    t.join();
}



